#include "../include/Poller.h"
#include "../include/Channel.h"

Poller::Poller() : _events(EpollSize)
{
#ifdef EPOLL_CLOEXEC
    _epollfd = epoll_create1(EPOLL_CLOEXEC);
#else
    _epollfd = epoll_create(EpollSize);
#endif
    if (_epollfd < 0)
    {
        ERR_LOG("epollfd 创建失败\n");
        exit(static_cast<int>(PollerExitCode::CRE_EPOLLFD_FAIL));
    }
    _channels.reserve(EpollSize);
}

Poller::~Poller()
{
    if (_epollfd > 0)
        ::close(_epollfd);
}

void Poller::UpdateEvents(Channel *channel)
{
    int fd = channel->getFd();
    if (!HasChannel(fd))
    {
        _channels[fd] = channel;
        if (!Update(EPOLL_CTL_ADD, channel))
        {
            _channels.erase(fd);
        }
    }
    else
    {
        if (!Update(EPOLL_CTL_MOD, channel))
        {
            if (!Update(EPOLL_CTL_ADD, channel))
            {
                _channels.erase(fd);
            }
        }
    }
}

void Poller::RemoveEvents(Channel *channel)
{
    int fd = channel->getFd();
    if (!HasChannel(fd))
        return;
    _channels.erase(fd);
    Update(EPOLL_CTL_DEL, channel);
}

void Poller::Poll(std::vector<Channel *> *active)
{
    int nfds = epoll_wait(_epollfd, _events.data(), _events.size(), -1);
    if (nfds < 0)
    {
        if (errno != EINTR)
        {
            ERR_LOG("epoll_wait 错误 %s\n", strerror(errno));
        }
        return;
    }

    for (int i = 0; i < nfds; i++)
    {
        Channel *channel = static_cast<Channel *>(_events[i].data.ptr);
        channel->setRevents(_events[i].events);
        active->push_back(channel);
    }

    if (nfds == _events.size())
        _events.resize(_events.size() * 2);
}

bool Poller::Update(int flag, Channel *channel)
{
    int fd = channel->getFd();
    struct epoll_event event;
    std::memset(&event, 0, sizeof(event));
    event.events = channel->getEvents();
    event.data.ptr = channel;

    int op = flag;
    int ret = epoll_ctl(_epollfd, op, fd, &event);
    if (ret < 0)
    {
        if (flag == EPOLL_CTL_ADD && errno == EEXIST)
        {
            op = EPOLL_CTL_MOD;
            ret = epoll_ctl(_epollfd, op, fd, &event);
        }
        else if (flag == EPOLL_CTL_MOD && errno == ENOENT)
        {
            op = EPOLL_CTL_ADD;
            ret = epoll_ctl(_epollfd, op, fd, &event);
        }
        else if (flag == EPOLL_CTL_DEL && (errno == ENOENT || errno == EBADF))
        {
            return true;
        }
    }

    if (ret < 0)
    {
        const char *opstr = (op == EPOLL_CTL_ADD) ? "ADD" : (op == EPOLL_CTL_MOD ? "MOD" : "DEL");
        ERR_LOG("epoll_ctl(%s) 失败, fd=%d, errno=%d(%s)\n", opstr, fd, errno, strerror(errno));
        if (errno == ENOMEM || errno == ENOSPC)
        {
            ERR_LOG("系统资源不足，考虑调整系统限制或优化连接管理\n");
        }
        return false;
    }
    return true;
}

bool Poller::HasChannel(int fd)
{
    auto it = _channels.find(fd);
    return it != _channels.end();
}
